﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.Reflection;

namespace KeyboardRemapper
{
   public partial class frmEditMacroList : Form
   {
      Bitmap KeyCodes;
      Bitmap bmpKeyboard;
      Dictionary<int, int> dicColorToCode = new Dictionary<int, int>();
      Dictionary<int, int> dicCodeToColor = new Dictionary<int, int>();
      Macro m_lastSelectedMacro = null;
      public frmEditMacroList()
      {
         InitializeComponent();
         KeyInterceptor.pPaused = true;
         bmpKeyboard = Image.FromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream("KeyboardRemapper.vkbd.png")) as Bitmap;
         pictureBox1.Image = bmpKeyboard;
         KeyCodes = Image.FromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream("KeyboardRemapper.vkbd_map.png")) as Bitmap;

         using (Stream stream = Assembly.GetExecutingAssembly()
                            .GetManifestResourceStream("KeyboardRemapper.KeybMap.txt"))
         using (StreamReader reader = new StreamReader(stream))
         {
            do
            {
               string line = reader.ReadLine();
               int from = line.BeforeString(",").ToInt(-1);
               int to = line.AfterString(",").ToInt(-1);
               if (to != -1)
               {
                  dicColorToCode[from] = to;
                  dicCodeToColor[to] = from;
               }
            }
            while (!reader.EndOfStream);
         }
         lstMacros.Items.AddRange(KeyInterceptor.pMacros.ToArray());
         lstMacros.SelectedIndexChanged += new EventHandler(txtMacros_SelectionChanged);
      }

      int GetColorForCode(int code)
      {
         if (dicCodeToColor.ContainsKey(code))
            return dicCodeToColor[code];
         else
            return -1;
      }

      void txtMacros_SelectionChanged(object sender, EventArgs e)
      {
         UpdateKeyboardDisplay();
      }

      private void UpdateKeyboardDisplay()
      {
         if (lstMacros.SelectedItem != null)
         {
            if (lstMacros.SelectedItem != m_lastSelectedMacro)
            {
               m_lastSelectedMacro = lstMacros.SelectedItem as Macro;
               Bitmap copy = new Bitmap(bmpKeyboard);

               if (m_lastSelectedMacro != null)
               {
                  List<byte> lHighlightBlue = m_lastSelectedMacro.pModifiers.Select(s => (byte)GetColorForCode(s)).ToList();
                  lHighlightBlue.Add((byte)GetColorForCode(m_lastSelectedMacro.pKey));
                  List<byte> lHighlightRed = m_lastSelectedMacro.pNotModifiers.Select(s => (byte)GetColorForCode(s)).ToList();

                  BitmapData bitmapData = copy.LockBits(new Rectangle(0, 0,
                       copy.Width, copy.Height),
                       ImageLockMode.WriteOnly,
                       PixelFormat.Format32bppArgb);
                  BitmapData keyboardData = KeyCodes.LockBits(new Rectangle(0, 0,
                                           KeyCodes.Width, KeyCodes.Height),
                                           ImageLockMode.ReadOnly,
                                           PixelFormat.Format32bppArgb);

                  unsafe
                  {
                     byte* imagePointer = (byte*)bitmapData.Scan0;
                     byte* keyboardPointer = (byte*)keyboardData.Scan0;
                     for (int i = 0; i < bitmapData.Height; i++)
                     {
                        for (int j = 0; j < bitmapData.Width; j++)
                        {
                           if (lHighlightBlue.Contains(keyboardPointer[1]) &&
                               lHighlightBlue.Contains(keyboardPointer[2]))
                           {
                              if (imagePointer[2] > 192) imagePointer[2] = 192;
                              if (imagePointer[1] > 192) imagePointer[1] = 192;
                              imagePointer[0] = 255;
                           }
                           if (lHighlightRed.Contains(keyboardPointer[1]) &&
                               lHighlightRed.Contains(keyboardPointer[2]))
                           {
                              if (imagePointer[0] > 192) imagePointer[2] = 192;
                              if (imagePointer[1] > 192) imagePointer[1] = 192;
                              imagePointer[2] = 255;
                           }
                           imagePointer += 4;
                           keyboardPointer += 4;
                        }
                        imagePointer += bitmapData.Stride - (bitmapData.Width * 4);
                        keyboardPointer += keyboardData.Stride - (keyboardData.Width * 4);
                     }
                  }
                  copy.UnlockBits(bitmapData);
                  KeyCodes.UnlockBits(keyboardData);
               }
               pictureBox1.Image = copy;
            }
         }
         else
         {
            pictureBox1.Image = bmpKeyboard;
         }
      }

      private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
      {
         /*label1.Text = KeyCodes.GetPixel(e.X, e.Y).R.ToString() + " -> " + KeyInterceptor.pCode;
         map[KeyCodes.GetPixel(e.X, e.Y).R] = KeyInterceptor.pCode;
         SaveDictionary();*/
         /*int key = KeyCodes.GetPixel(e.X, e.Y).R;
         if (dicColorToCode.ContainsKey(key))
            lblKeyCode.Text = dicColorToCode[KeyCodes.GetPixel(e.X, e.Y).R].ToString();
         else
            lblKeyCode.Text = "";*/
      }

      void SaveDictionary()
      {
         File.WriteAllLines("map.txt", dicColorToCode.Select(o => o.Key + "," + o.Value).ToList());
      }

      private void btnSave_Click(object sender, EventArgs e)
      {
         KeyInterceptor.pMacros = lstMacros.Items.OfType<Macro>().ToList();
         KeyInterceptor.InitMacros();
         KeyInterceptor.WriteMacros();
         Close();
      }

      private void vkbd_FormClosing(object sender, FormClosingEventArgs e)
      {
         KeyInterceptor.pPaused = false;
      }

      private void btnCancel_Click(object sender, EventArgs e)
      {
         Close();
      }

      private void lstMacros_DoubleClick(object sender, EventArgs e)
      {
         if (lstMacros.SelectedItem != null)
         {
            Macro m = lstMacros.SelectedItem as Macro;
            m = frmEditMacro.EditMacro(m);
            if (m != null)
            {
               lstMacros.Items[lstMacros.SelectedIndex] = m;
               m_lastSelectedMacro = null;
               UpdateKeyboardDisplay();
            }
         }
      }

      private void btnAddMacro_Click(object sender, EventArgs e)
      {
         Macro m = frmEditMacro.EditMacro(null);
         if (m != null)
         {
            int visibleItems = lstMacros.Height / lstMacros.ItemHeight;
            lstMacros.Items.Add(m);
            lstMacros.SelectedItem = m;
            lstMacros.TopIndex = lstMacros.Items.Count - visibleItems;
            m_lastSelectedMacro = null;
            UpdateKeyboardDisplay();
         }
      }

      private void btnRemoveMacro_Click(object sender, EventArgs e)
      {
         if (lstMacros.SelectedItem != null)
         {
            DialogResult dr = MessageBox.Show("You are about to remove the selected macro :\n" +
               lstMacros.SelectedItem.ToString() + "\n\nPress Ok to confirm", "Warning", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
            if (dr == System.Windows.Forms.DialogResult.OK)
               lstMacros.Items.Remove(lstMacros.SelectedItem);
         }
      }
   }
}

